#include "stdafx.h"
#include "Tracing.h"

#include "Ray.h"
#include "Scene.h"
#include "RenderTarget.h"
#include "Material.h"

#include "Geometry.h"
#include "Blob.h"
#include "Algeb.h"

#include "perlin.h"

using namespace rt;

static const uint RECURSION_LIMIT = 5;
static const XMVECTOR DEFAULT_COLOR = XMVectorSet(0.5f, 0.5f, 0.5f, 0.0f);

static float timer = 0.0f;

void rt::renderImage(RT_Memory & renderTarget, Scene & scene, int width, int height, bool previewRender)
{
	int w = width;
	int h = height;

	timer++;
	if(scene.BlobsNum > 0)
	{
		scene.Blobs[0].Balls[0].Center.m128_f32[0] = sinf(timer / 20) * 3 + 3;
		scene.Blobs[0].Balls[1].Center.m128_f32[1] = sinf(timer / 10) * 3 + 3;
		scene.Blobs[0].Balls[2].Center.m128_f32[0] = sinf(timer / 10) * 3 + 3;
		scene.Blobs[0].Balls[2].Center.m128_f32[1] = sinf(timer / 20) * 3 + 3;
	}

	scene.GetEditableCamera().SetResolution(w, h);

	Scene::LightList lights = scene.GetLights();

	Color ambient = scene.GetAmbientColor();

	Vec3 startRay;
	Vec3 currRayDir, rayDirAdvanceX, rayDirAdvanceY;
	scene.GetCamera().GetRayGenerationInfo(startRay, rayDirAdvanceX, rayDirAdvanceY);

	Vec3 cameraPos = scene.GetCamera().GetPosition();

	//Vec3 currRowStartRayDir = currRayDir = startRay;

	
	for(int y=0 ; y<h ; y+=2)
	{
		Vec3 currRowStartRayDir = startRay + y * rayDirAdvanceY;//+= 2 * rayDirAdvanceY;

		#pragma omp parallel for
		for(int x=0 ; x<w ; x+=2)
		{
			currRayDir = currRowStartRayDir + x * rayDirAdvanceX;//+= 2 * rayDirAdvanceX;

			//Ray ray(cameraPos, normalize(currRayDir));
			Ray4_SingleOrigin packet;
			packet.Orig = XMVectorSet(cameraPos.x, cameraPos.y, cameraPos.z, 0.0f);

			Vec3 curRayDirNorm0 = normalize(currRayDir);
			Vec3 curRayDirNorm1 = normalize(currRayDir + rayDirAdvanceX);
			Vec3 curRayDirNorm2 = normalize(currRayDir + rayDirAdvanceY);
			Vec3 curRayDirNorm3 = normalize(currRayDir + rayDirAdvanceX + rayDirAdvanceY);
			packet.DirX = XMVectorSet(curRayDirNorm0.x, curRayDirNorm1.x, curRayDirNorm2.x, curRayDirNorm3.x);
			packet.DirY = XMVectorSet(curRayDirNorm0.y, curRayDirNorm1.y, curRayDirNorm2.y, curRayDirNorm3.y);
			packet.DirZ = XMVectorSet(curRayDirNorm0.z, curRayDirNorm1.z, curRayDirNorm2.z, curRayDirNorm3.z);

			RayPacketTraceResult result;
			traceSingleOriginRayPacket(packet, scene, result, 0);

			RT_Pixel pixel;
			Color color(result.Colors[0].m128_f32[0], result.Colors[0].m128_f32[1], result.Colors[0].m128_f32[2], result.Colors[0].m128_f32[3]);
			color.normalizeAndScale(255.0f);
			pixel.R = (byte)color.R; pixel.G = (byte)color.G; pixel.B = (byte)color.B;
			renderTarget.SetPixel(x, y, pixel);

			color = Color(result.Colors[1].m128_f32[0], result.Colors[1].m128_f32[1], result.Colors[1].m128_f32[2], result.Colors[1].m128_f32[3]);
			color.normalizeAndScale(255.0f);
			pixel.R = (byte)color.R; pixel.G = (byte)color.G; pixel.B = (byte)color.B;
			renderTarget.SetPixel(x + 1, y, pixel);

			color = Color(result.Colors[2].m128_f32[0], result.Colors[2].m128_f32[1], result.Colors[2].m128_f32[2], result.Colors[2].m128_f32[3]);
			color.normalizeAndScale(255.0f);
			pixel.R = (byte)color.R; pixel.G = (byte)color.G; pixel.B = (byte)color.B;
			renderTarget.SetPixel(x, y + 1, pixel);

			color = Color(result.Colors[3].m128_f32[0], result.Colors[3].m128_f32[1], result.Colors[3].m128_f32[2], result.Colors[3].m128_f32[3]);
			color.normalizeAndScale(255.0f);
			pixel.R = (byte)color.R; pixel.G = (byte)color.G; pixel.B = (byte)color.B;
			renderTarget.SetPixel(x + 1, y + 1, pixel);			
		}
	}
}

static void getObjectIntersectionData(const Scene & scene, XMVECTOR intersPoint, ObjectType type, size_t index, IntersectionData & data)
{
	switch(type)
	{
	case OBJECT_SPHERE:
		GetSphereIntersectionData(scene.Spheres[index], intersPoint, data);
		data.Material = scene.SphereMats[index];
		break;

	case OBJECT_PLANE:
		GetPlaneIntersectionData(scene.Planes[index], intersPoint, data);
		data.Material = scene.PlaneMats[index];
		break;

	case OBJECT_BOX:
		GetBoxIntersectionData(scene.Boxes[index], intersPoint, data);
		data.Material = scene.BoxMats[index];
		break;

	case OBJECT_BLOB:
		GetBlobIntersectionData(scene.Blobs[index], intersPoint, data);
		data.Material = scene.BlobMats[index];
		break;

	case OBJECT_ALGEB:
		GetAlgebIntersectionData(scene.Algebs[index], intersPoint, data);
		data.Material = scene.AlgebMats[index];
		break;
	}
}


static void pixelLighting(const Scene & scene, XMVECTOR intersPt, const IntersectionData & intData, const Ray & ray, XMVECTOR & outColor)
{
	size_t lightsSize = scene.GetLights().size();

	XMVECTOR diffAccum = scene.AmbientColor;
	XMVECTOR specAccum = XMVectorZero();

	Material * mat = intData.Material;
	XMVECTOR normal = intData.Normal;

	for(size_t lightIdx = 0; lightIdx < lightsSize; ++lightIdx)
	{
		Light * light = scene.GetLights()[lightIdx];

		XMVECTOR toLight = XMVectorSubtract(light->Position, intersPt);
		XMVECTOR toLightLen = XMVector3Length(toLight);
		toLight = XMVector3Normalize(toLight);

		Ray toLightRay = Ray(intersPt, toLight);

		if(IntersectPlanes_Any_1Ray(scene.Planes, scene.PlanesNum, toLightRay, toLightLen)) continue;
		if(IntersectSpheres_Any_1Ray(scene.Spheres, scene.SpheresNum, toLightRay, toLightLen)) continue;
		if(IntersectBoxes_Any_1Ray(scene.Boxes, scene.BoxesNum, toLightRay, toLightLen)) continue;

		const float diffTerm = XMVectorGetX(XMVectorSaturate(XMVector3Dot(normal, toLight)));

		const XMVECTOR refl = XMVectorSubtract(toLight, XMVectorMultiply(XMVectorReplicate(2.0f), XMVectorMultiply(XMVector3Dot(toLight, normal), normal)));
		const float specBase = XMVectorGetX(XMVectorSaturate(XMVectorNegate(XMVector3Dot(refl, XMVectorNegate(ray.Dir)))));
		// if(base > 0.9f)

		float specTerm = 0.0f;
		//UINT isSpecBaseOverThresh;
		//XMVectorGreaterR(&isSpecBaseOverThresh, specBase, XMVectorReplicate(0.9f));
		//if(XMComparisonAllTrue(isSpecBaseOverThresh))
		//	specTerm = XMVectorPow(specBase, XMVectorReplicate(mat->_specularPower));

		if(specBase > 0.9f)
		{
			specTerm = powf(specBase, mat->SpecularPower);
		}
		
		//const float strength = light->Strength * powf( 1.0f - saturate( XMVectorGetX(toLightLen) / light->Radius ), light->Falloff );
		const float strength = light->Strength *  ( 1.0f - saturate( XMVectorGetX(toLightLen) / light->Radius ) );

		diffAccum = XMVectorAdd( diffAccum, XMVectorMultiply(light->Diffuse, XMVectorReplicate(diffTerm * strength)) );
		specAccum = XMVectorAdd( specAccum, XMVectorMultiply(light->Diffuse, XMVectorReplicate(specTerm * strength)) );
	}

	XMVECTOR diffuseColor = XMVectorMultiply(diffAccum, mat->Diffuse);
	if(mat->ProcTex != Material::NONE) diffuseColor = XMVectorMultiply(diffuseColor, mat->GetProcTexColor(intData.TexCoords));
	outColor = XMVectorAdd( outColor, diffuseColor );
	outColor = XMVectorAdd( outColor, XMVectorMultiply(specAccum, mat->Specular) );
}

static void shadePacket(const Ray4 & packet, const Scene & scene, XMVECTOR intIdx, XMVECTOR intDepth, ObjectType * intObjType, XMVECTOR intType, RayPacketTraceResult & result, uint recursionDepth)
{
	IntersectionData intDatas[4];

	Ray4 transpPacket, reflPacket;

	bool traceTransp = false, traceRefl = false;

	size_t lightsNum = scene.GetLights().size();

	for (uint i = 0; i < 4 ; i++)
	{
		// intersection found
		if(intObjType[i] != OBJECT_NONE)
		{
			XMVECTOR rayDir = packet.GetDir(i);
			XMVECTOR rayOrig = packet.GetOrig(i);
			XMVECTOR intersPt = XMVectorMultiplyAdd(rayDir, XMVectorReplicate(XMVectorGetByIndex(intDepth, i)), rayOrig);
			getObjectIntersectionData(scene, intersPt, intObjType[i], intIdx.m128_i32[i], intDatas[i]);

			Material * mat = intDatas[i].Material;

			XMVECTOR normalOutside = intDatas[i].Normal;
			XMVECTOR normal = intDatas[i].Normal;
			uint intersType = XMVectorGetIntByIndex(intType, i);
			if(intersType == 0)
				normal = XMVectorNegate(normal);

			//color = XMVectorSet(mat->_ambient.R, mat->_ambient.G, mat->_ambient.B, 1.0f);

			Ray ray(rayOrig, rayDir);
			
			
			pixelLighting(scene, intersPt, intDatas[i], ray, result.Colors[i]);

			XMVECTOR rayDirNeg = XMVectorNegate(ray.Dir);
			if(mat->Transparency > 0.0f)
			{
				//Ray behindSurfRay(intersPt, ray._direction);
				
				const float refrIdx = intersType ? mat->RefractionIndexAirToObject : mat->RefractionIndexObjectToAir;
				const float cosI = XMVectorGetX(XMVector3Dot(normal, rayDirNeg));
				const float sinT2 = refrIdx * refrIdx * (1.0f - cosI * cosI);
				XMVECTOR refrDir = XMVectorAdd(
					XMVectorMultiply(ray.Dir, XMVectorReplicate(refrIdx)),
					XMVectorMultiply(normal, XMVectorReplicate(refrIdx * cosI - sqrtf(1.0f - sinT2))));
				//if(sinT2 > 1.0f)
				//	refrDir = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

				transpPacket.SetRay(intersPt, refrDir, i);
				traceTransp = true;
			}

			if(mat->Reflectance > 0.0f)
			{
				
				XMVECTOR reflDir = XMVectorAdd(XMVectorMultiply(XMVectorReplicate(2.0f), XMVectorMultiply(XMVector3Dot(normal, rayDirNeg), normal)), ray.Dir);
				//Ray reflRay(intersPt, reflDir);
				reflPacket.SetRay(intersPt, reflDir, i);
				traceRefl = true;
			}

			//pixelTransparancyReflection(scene, intersPt, normal, ray, mat, result.Colors[i]);
		}
	}

	RayPacketTraceResult transpResult, reflResult;
	if(traceTransp) traceRayPacket(transpPacket, scene, transpResult, recursionDepth);
	if(traceRefl) traceRayPacket(reflPacket, scene, reflResult, recursionDepth);
	

	for (uint i = 0; i < 4 ; i++)
	{
		// intersection found
		if(intObjType[i] != OBJECT_NONE)
		{
			Material * mat = intDatas[i].Material;

			if(mat->Transparency > 0.0f)
			{
				result.Colors[i] = XMVectorAdd(
					XMVectorMultiply(XMVectorReplicate(1.0f - mat->Transparency), result.Colors[i]),
					XMVectorMultiply(XMVectorReplicate(mat->Transparency), transpResult.Colors[i])
					);
			}
			if(mat->Reflectance > 0.0f)
			{
				result.Colors[i] = XMVectorAdd(
					XMVectorMultiply(XMVectorReplicate(1.0f - mat->Reflectance), result.Colors[i]),
					XMVectorMultiply(XMVectorReplicate(mat->Reflectance), reflResult.Colors[i])
					);
			}
		}
	}
}

void rt::traceSingleOriginRayPacket(const Ray4_SingleOrigin & packet, const Scene & scene, RayPacketTraceResult & result, uint recursionDepth)
{
	recursionDepth++;
	if(recursionDepth > RECURSION_LIMIT)
	{
		result.Colors[0] = DEFAULT_COLOR;	result.Colors[1] = DEFAULT_COLOR;
		result.Colors[2] = DEFAULT_COLOR;	result.Colors[3] = DEFAULT_COLOR;
		return;
	}

	result.Colors[0] = ColorA::BLACK;
	result.Colors[1] = ColorA::BLACK;
	result.Colors[2] = ColorA::BLACK;
	result.Colors[3] = ColorA::BLACK;

	XMVECTOR depth = XMVectorSplatInfinity();
	static const uint INV_IDX = 999999;
	XMVECTOR newIntIdx, intIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	ObjectType intObjType[4] = { OBJECT_NONE };

	// intersect planes
	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectPlanes_All_4RaysSingleOrigin(scene.Planes, scene.PlanesNum, packet, newIntIdx, depth);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_PLANE; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_PLANE; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_PLANE; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_PLANE; }

	// intersect spheres
	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectSpheres_All_4RaysSingleOrigin(scene.Spheres, scene.SpheresNum, packet, newIntIdx, depth);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_SPHERE; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_SPHERE; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_SPHERE; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_SPHERE; }

	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectBoxes_All_4RaysSingleOrigin(scene.Boxes, scene.BoxesNum, packet, newIntIdx, depth);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_BOX; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_BOX; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_BOX; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_BOX; }

	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectBlobs_All_4RaysSingleOrigin(scene.Blobs, scene.BlobsNum, packet, newIntIdx, depth);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_BLOB; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_BLOB; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_BLOB; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_BLOB; }

	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectAlgebs_All_4RaysSingleOrigin(scene.Algebs, scene.AlgebsNum, packet, newIntIdx, depth);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_ALGEB; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_ALGEB; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_ALGEB; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_ALGEB; }

	//// intersect boxes
	//XMVECTOR tmpDepth;

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[0]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.Orig, packet.GetDir(0)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intType[0] = OBJECT_BOX; depth.m128_f32[0] = tmpDepth.m128_f32[0]; }

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[1]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.Orig, packet.GetDir(1)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[0]; intType[1] = OBJECT_BOX; depth.m128_f32[1] = tmpDepth.m128_f32[0]; }

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[2]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.Orig, packet.GetDir(2)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[0]; intType[2] = OBJECT_BOX; depth.m128_f32[2] = tmpDepth.m128_f32[0]; }

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[3]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.Orig, packet.GetDir(3)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[0]; intType[3] = OBJECT_BOX; depth.m128_f32[3] = tmpDepth.m128_f32[0]; }


	shadePacket(packet, scene, intIdx, depth, intObjType, XMVectorTrueInt(), result, recursionDepth);

	recursionDepth--;
}

void rt::traceRayPacket(const Ray4 & packet, const Scene & scene, RayPacketTraceResult & result, uint recursionDepth)
{
	recursionDepth++;
	if(recursionDepth > RECURSION_LIMIT)
	{
		result.Colors[0] = DEFAULT_COLOR;	result.Colors[1] = DEFAULT_COLOR;
		result.Colors[2] = DEFAULT_COLOR;	result.Colors[3] = DEFAULT_COLOR;
		return;
	}

	result.Colors[0] = ColorA::BLACK;
	result.Colors[1] = ColorA::BLACK;
	result.Colors[2] = ColorA::BLACK;
	result.Colors[3] = ColorA::BLACK;

	XMVECTOR depth = XMVectorSplatInfinity();
	XMVECTOR intType = XMVectorTrueInt();
	static const uint INV_IDX = 999999;
	XMVECTOR newIntIdx, intIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	ObjectType intObjType[4] = { OBJECT_NONE };

	// intersect planes
	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectPlanes_All_4Rays(scene.Planes, scene.PlanesNum, packet, newIntIdx, depth, intType);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_PLANE; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_PLANE; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_PLANE; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_PLANE; }

	// intersect spheres
	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectSpheres_All_4Rays(scene.Spheres, scene.SpheresNum, packet, newIntIdx, depth, intType);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_SPHERE; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_SPHERE; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_SPHERE; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_SPHERE; }

	newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	IntersectBoxes_All_4Rays(scene.Boxes, scene.BoxesNum, packet, newIntIdx, depth, intType);
	if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intObjType[0] = OBJECT_BOX; }
	if(newIntIdx.m128_u32[1] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[1]; intObjType[1] = OBJECT_BOX; }
	if(newIntIdx.m128_u32[2] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[2]; intObjType[2] = OBJECT_BOX; }
	if(newIntIdx.m128_u32[3] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[3]; intObjType[3] = OBJECT_BOX; }

	// intersect boxes
	//XMVECTOR tmpDepth;

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[0]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.GetOrig(0), packet.GetDir(0)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[0] = newIntIdx.m128_u32[0]; intType[0] = OBJECT_BOX; depth.m128_f32[0] = tmpDepth.m128_f32[0]; }

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[1]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.GetOrig(1), packet.GetDir(1)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[1] = newIntIdx.m128_u32[0]; intType[1] = OBJECT_BOX; depth.m128_f32[1] = tmpDepth.m128_f32[0]; }

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[2]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.GetOrig(2), packet.GetDir(2)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[2] = newIntIdx.m128_u32[0]; intType[2] = OBJECT_BOX; depth.m128_f32[2] = tmpDepth.m128_f32[0]; }

	//newIntIdx = XMVectorSetInt(INV_IDX, INV_IDX, INV_IDX, INV_IDX);
	//tmpDepth = XMVectorReplicate(depth.m128_f32[3]);
	//IntersectBoxes_All_1Ray(scene.Boxes, scene.BoxesNum, Ray(packet.GetOrig(3), packet.GetDir(3)), newIntIdx, tmpDepth);
	//if(newIntIdx.m128_u32[0] != INV_IDX) { intIdx.m128_u32[3] = newIntIdx.m128_u32[0]; intType[3] = OBJECT_BOX; depth.m128_f32[3] = tmpDepth.m128_f32[0]; }

	shadePacket(packet, scene, intIdx, depth, intObjType, intType, result, recursionDepth);

	recursionDepth--;
}
